package com.example.myapplication.ocr;


import android.util.Log;

import org.jsoup.Jsoup;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
//import org.opencv.highgui.Highgui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.ml.ANN_MLP;

import java.util.ArrayList;
import java.util.List;

public class PictureManager {
    private static final String TAG="PictureManager";
//    private static final byte[] WHITE=new byte[]{(byte)255};
//    private static final byte[] BLACK=new byte[]{(byte)0};
    private static final int WHITE=255;
    private static final int BLACK=0;
    private boolean outputImage=true;
    //private JLabel jLabelImage;
    public PictureManager(String fileName) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//        this.image= Highgui.imread(fileName);
//        ANN_MLP mlp = ANN_MLP.create();
//        mlp.tra
    }



    /**
     * 图片画质处理
     * @param image
     * @return
     */
    public  Mat threshMatImage(Mat image) {
//        Mat loadeMatImage = new Mat();
        //灰度处理
        Imgproc.cvtColor(image,image,Imgproc.COLOR_RGB2GRAY);
        //二值化处理
        Mat binaryMat = new Mat(image.height(), image.width(), CvType.CV_8UC1);
        Imgproc.threshold(image, binaryMat,150, 255, Imgproc.THRESH_BINARY);

//        Log.e("PictureManager","segmentImage  erode ");
        //图像腐蚀
//        Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
//                new Size(1,1));
//        Imgproc.erode(binaryMat, loadeMatImage,element);
//        Log.e("PictureManager","segmentImage  erode = "+loadeMatImage);
//        loadeMatImage = image;
//        loadeMatImage = binaryMat;
//        Imgproc.dilate(binaryMat,loadeMatImage,new Mat());
//        loadeMatImage=naiveRemoveNoise(binaryMat,1);
//        contoursRemoveNoise(loadeMatImage,10);
//        loadeMatImage=binaryMat;
        return binaryMat;
    }

    public  void segmentImage(){

        Mat srcImgMat = Imgcodecs.imread("/mnt/sdcard/aaa/captcha.svl");
        Mat imgMat=threshMatImage(srcImgMat);
        Log.e("PictureManager","segmentImage  setMatImage = "+imgMat);
        if(outputImage){
            Imgcodecs.imwrite("/mnt/sdcard/aaa/img"+".jpg",imgMat);
        }
        //cvShowImage cvFindContours cvBoundingRect cvSetImageROI
        ArrayList<MatOfPoint> list=new ArrayList<MatOfPoint>();
        Mat hierarchy=new Mat();
        Imgproc.findContours(imgMat,list,hierarchy,Imgproc.RETR_EXTERNAL,Imgproc.CHAIN_APPROX_SIMPLE);
        Log.e("PictureManager","segmentImage  findContours = "+list.size());
        for(int i=0;i<list.size();i++){
            MatOfPoint point=list.get(i);
            double area = Imgproc.contourArea(point);
            if(area > 10){
                Rect rect = Imgproc.boundingRect(point);
                Mat roiMat=new Mat(imgMat,rect);
                if(outputImage){
                    Imgcodecs.imwrite("/mnt/sdcard/aaa/img_"+i+".jpg",roiMat);
                }
                Log.e("PictureManager","segmentImage = "+ i);
            }


        }


    }

    public Mat cutImage(Mat srcImg,Point p1,Point p2){
        if(srcImg == null) throw new NullPointerException("cutImage srcImg is null");
        Rect rect = new Rect(p1,p2);
        Mat cutMat=new Mat(srcImg,rect).clone();

        return cutMat;
    }

    public Mat cutImage(Mat srcImg,Point p1,double width ,double height){
        if(srcImg == null) throw new NullPointerException("cutImage srcImg is null");
        Rect rect = new Rect(p1,new Size(width,height));
        Mat cutMat=new Mat(srcImg,rect).clone();

        return cutMat;
    }

    public Mat horizontalProjectionCutImage(Mat srcImg){
        Mat bImg=srcImg;
        Log.e("PictureManager","channels = "+srcImg.channels());
        if(srcImg.channels()>1){
            bImg=threshMatImage(srcImg);
        }
        int rows=bImg.rows();
        int cols=bImg.cols();
        int[] projectionArray = new int[rows];
        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                byte[] color=new byte[1];
                bImg.get(i,j,color);
                if(color[0] == (byte) 255){
                    if(projectionArray[i] > 1) break;
                    projectionArray[i]++;
                    Log.e("PictureManager","horizontalProjectionCutImage i = "+i+" projectionArray = "+projectionArray[i]);
                }

            }
        }

        int startIndex=0;
        int endIndex=0;
        for(int i=0;i<rows;i++){
            if(projectionArray[i] > 0){
                startIndex=i;
                break;
            }
        }

        for(int i=rows-1;i>0;i--){
            if(projectionArray[i] > 0){
                endIndex=i;
                break;
            }
        }
        Log.e("PictureManager","startIndex = "+startIndex+" endIndex = "+endIndex);
        Rect rect=new Rect(new Point(0,startIndex),new Size(cols,endIndex-startIndex));
        Mat resultImg=new Mat(srcImg,rect).clone();
        return resultImg;

    }

    //defThresh = 12
    public List<Mat> verticalProjectionCutImage(Mat srcImg,int defThresh){
        ArrayList<Mat> imgList=new ArrayList<>();
        Mat bImg=srcImg;
        Log.e("PictureManager","channels = "+srcImg.channels());
        if(srcImg.channels()>1){
            bImg=threshMatImage(srcImg);
        }
//        Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
//                new Size(1,1));
        Mat dilateImg=new Mat();
        Imgproc.dilate(bImg,dilateImg,new Mat(2,2,CvType.CV_8UC1));
        if(outputImage){
            Imgcodecs.imwrite("/mnt/sdcard/aaa/img_cut_dilate.jpg",dilateImg);
        }
        int rows=dilateImg.rows();
        int cols=dilateImg.cols();
        int[] projectionArray = new int[cols];
        for(int i=0;i<cols;i++){
            for(int j=0;j<rows;j++){
                byte[] color=new byte[1];
                dilateImg.get(j,i,color);
                if(color[0] == (byte) 255){
                    if(projectionArray[i] > 1) break;
                    projectionArray[i]++;
                    Log.e("PictureManager","horizontalProjectionCutImage i = "+i+" projectionArray = "+projectionArray[i]);
                }

            }
        }

        int startIndex=0;
        int endIndex=0;
        boolean isRoi=false;
        int thresh=defThresh;
        while (true){
            for(int i=0;i<cols;i++){
                if(!isRoi && projectionArray[i] > 0){
                    startIndex=i;
                    isRoi=true;
                }
                if(isRoi && projectionArray[i] == 0){
                    endIndex=i;
                    if(endIndex-startIndex < thresh) continue;
                    isRoi=false;
                    Log.e("PictureManager","startIndex = "+startIndex+" endIndex = "+endIndex);
                    Rect rect=new Rect(new Point(startIndex,0),new Size(endIndex-startIndex,rows));
                    Mat resultImg=new Mat(srcImg,rect).clone();
                    imgList.add(resultImg);
                }
            }
            //如果分割图片大于或小于3张则阈值调整，重新分割
            if(imgList.size() > 3){
                thresh++;
                if(thresh>20) break;
            }else if(imgList.size() < 3){
                thresh--;
                if(thresh<=0){
                    Log.e(TAG,"thresh = "+thresh+" imgList size = "+imgList.size());
                    break;
                }
            }else {
                break;
            }
        }


        return imgList;

    }

    public void divisionImage(){

    }


    public Point matchImage(Mat srcImgMat, Mat templateImgMat ,int method){
//        Mat srcImgMat = Imgcodecs.imread("/mnt/sdcard/aaa/captcha.svl");
//        Mat templateImgMat = threshMatImage(Imgcodecs.imread("/mnt/sdcard/aaa/img_template.jpg"));
        if(srcImgMat == null || templateImgMat == null){
            Log.e(TAG,"params error,srcImgMat = "+srcImgMat+" templateImgMat = "+templateImgMat);
            return null;
        }
        Mat imgMat=srcImgMat.clone();
        if(srcImgMat.channels()>1){
            imgMat=threshMatImage(imgMat);
        }

        int rows=imgMat.rows()-templateImgMat.rows()+1;
        int cols=imgMat.cols()-templateImgMat.cols()+1;
        Mat resultImg=new Mat(rows,cols, imgMat.type());
        Log.d(TAG,"imgMat type = "+ imgMat.type()+" depth = "+imgMat.depth()+";" +
                " tmpImgMat type = "+templateImgMat.type()+" depth = "+templateImgMat.depth() +";" +
                " resultImg  type = "+resultImg.type()+" depth = "+resultImg.depth());
        Imgproc.matchTemplate(imgMat,templateImgMat,resultImg, method);
//        Imgcodecs.imwrite("/mnt/sdcard/aaa/img_result"+".jpg",resultImg);
        Point matchLoc;
        Core.MinMaxLocResult locResult = Core.minMaxLoc(resultImg);
        Core.normalize(resultImg,resultImg);
        if(method == Imgproc.TM_SQDIFF || method == Imgproc.TM_SQDIFF_NORMED){
            matchLoc=locResult.minLoc;
        }else {
            matchLoc=locResult.maxLoc;
        }
        //matchLoc x = 107.0 y = 78.0
        Log.d(TAG,"matchLoc x = "+ matchLoc.x+" y = "+matchLoc.y);
        Imgproc.rectangle(imgMat,matchLoc,new Point(matchLoc.x+templateImgMat.cols(),matchLoc.y+templateImgMat.rows()),new Scalar(255));
        if(outputImage){
            Imgcodecs.imwrite("/mnt/sdcard/aaa/img_match"+"_"+ matchLoc.x+"_"+ matchLoc.y+".jpg",imgMat);
        }

        return matchLoc;
    }



    public Mat naiveRemoveNoise(Mat image,int pNum){

            //naive remove noise
            int i,j,m,n,nValue,nCount;
            int nWidth = image.width();
            int nHeight = image.height();
            //set boundry to be white
            for (i = 0; i < nWidth ; ++i)
            {

                for(int k=0;k<3;k++){
                    image.put(i,k,BLACK);
                    image.put(i,nHeight-1-k,BLACK);
                }
//                setPixel(i,0,WHITE);
//                setPixel(i,nHeight-1,WHITE);
            }
            for (i = 0; i < nHeight ; ++i)
            {
                for(int k=0;k<3;k++){
                    image.put(k,i,BLACK);
                    image.put(nWidth-1-k,i,BLACK);
                }
//                setPixel(0,i,WHITE);
//                setPixel(nWidth-1,i,WHITE);
            }
//            //if the neighbor of a point is white but it is black, delete it
//            for (j = 1; j < nHeight; ++j)
//                for (i = 1; i < nWidth; ++i) {
//                    nValue = image.get(i,j)!=null?(int)image.get(i,j)[0]:0;
//                    Log.e("PictureManager","removeNoise nValue = "+ nValue);
////                    nValue = getPixel(i, j);
//                    if (nValue==255) {
//                        nCount = 0;
//                        for (m = i - 1; m <= i + 1; ++m)
//                            for (n = j - 1; n <= j + 1; ++n) {
//                                if (/*!getPixel(m, n)*/image.get(m,n)!=null && (int)image.get(m,n)[0]==255)
//                                    nCount++;
//                            }
//                        if (nCount <= pNum){
////                            setPixel(i, j, WHITE);
//                            image.put(i,j,BLACK);
//                            Log.e("PictureManager","removeNoise image put BLACK ");
//                        }
//                    } else {
//                        nCount = 0;
//                        for (m = i - 1; m <= i + 1; ++m)
//                            for (n = j - 1; n <= j + 1; ++n) {
//                                if (/*!getPixel(m, n)*/image.get(m,n)!=null && (int)image.get(m,n)[0]==255)
//                                    nCount++;
//                            }
//                        if (nCount >= 7){
////                            setPixel(i, j, BLACK);
//                            image.put(i,j,WHITE);
//                            Log.e("PictureManager","removeNoise image put WHITE ");
//                        }
//
//                    }
//                }

                return image;
    }

    public void contoursRemoveNoise(Mat image,double pArea)
    {
        int i,j;
        int color = 1;
        int nWidth = 100/*image.width()*/;
        int nHeight = 50/*image.height()*/;
        byte[] value = new byte[1];
                Log.e("PictureManager","contoursRemoveNoise nWidth = "+nWidth+" nHeight = "+nHeight);
        for (i = 0; i < nWidth; ++i)
            for (j = 0; j < nHeight; ++j)
            {

//                int value = image.get(i,j)!=null?(int)image.get(i,j)[0]:-1;
                value[0]=0;
                int rtn=image.get(i,j,value);
                Log.e("PictureManager","contoursRemoveNoise image.get(i,j) "+i+","+j+":"+value[0] +" rtn = "+rtn);
                if ( /*!getPixel(i,j)*/ (int)value[0]==WHITE)
                {
                    //FloodFill each point in connect area using different color
                    Mat mask=new Mat();
                    Log.e("PictureManager","contoursRemoveNoise i = "+i+" j = "+j);
                    Imgproc.floodFill(image,mask,new Point(i,j), new Scalar((double) 255));
//                    floodFill(m_Mat,cvPoint(i,j),cvScalar(color));
                    color++;
                }
            }

//        int ColorCount[255] = { 0 };
        int[] ColorCount = new int[2];
        for (i = 0; i < nWidth; ++i)
        {
            for (j = 0; j < nHeight; ++j)
            {
                value[0]=0;
                image.get(i,j,value);
                //caculate the area of each area
                if (/*getPixel(i,j) != 255*/(int)value[0]!=BLACK)
                {
//                    ColorCount[getPixel(i,j)]++;
                    ColorCount[1]++;

                }
            }
        }
        //get rid of noise point
        for (i = 0; i < nWidth; ++i)
        {
            for (j = 0; j < nHeight; ++j)
            {
                if (ColorCount[/*getPixel(i,j)*/1] <= pArea)
                {
//                    setPixel(i,j,WHITE);
                    image.put(i,j,BLACK);
                }
            }
        }
        for (i = 0; i < nWidth; ++i)
        {
            for (j = 0; j < nHeight; ++j)
            {
                value[0]=0;
                image.get(i,j,value);
                if (/*getPixel(i,j) < WHITE */(int)value[0]< WHITE)
                {
//                    setPixel(i,j,BLACK);
                    image.put(i,j,BLACK);
                }
            }
        }
    }

    /*

    void Image::NaiveRemoveNoise(int pNum)
{
    //naive remove noise
    int i,j,m,n,nValue,nCount;
    int nWidth = getWidth();
    int nHeight = getHeight();
    //set boundry to be white
    for (i = 0; i < nWidth ; ++i)
    {
        setPixel(i,0,WHITE);
        setPixel(i,nHeight-1,WHITE);
    }
    for (i = 0; i < nHeight ; ++i)
    {
        setPixel(0,i,WHITE);
        setPixel(nWidth-1,i,WHITE);
    }
    //if the neighbor of a point is white but it is black, delete it
    for (j = 1; j < nHeight; ++j)
        for (i = 1; i < nWidth; ++i)
        {
            nValue = getPixel(i,j);
            if ( !nValue )
            {
                nCount = 0;
                for (m = i-1; m <= i+1; ++m)
                    for (n = j-1; n <= j+1; ++n)
                    {
                        if( !getPixel(m,n) )
                            nCount++;
                    }
                if (nCount <= pNum)
                    setPixel(i,j,WHITE);
            }
            else
            {
                nCount = 0;
                for (m = i-1; m <= i+1; ++m)
                    for (n = j-1; n <= j+1; ++n)
                    {
                        if( !getPixel(m,n) )
                            nCount++;
                    }
                if (nCount >= 7)
                    setPixel(i,j,BLACK);
            }
        }
}
     */

    /*

    void Image::ContoursRemoveNoise(double pArea)
{
    int i,j;
    int color = 1;
    int nHeight = getHeight();
    int nWidth = getWidth();

    for (i = 0; i < nWidth; ++i)
        for (j = 0; j < nHeight; ++j)
        {
            if ( !getPixel(i,j) )
            {
                //FloodFill each point in connect area using different color
                floodFill(m_Mat,cvPoint(i,j),cvScalar(color));
                color++;
            }
        }

    int ColorCount[255] = { 0 };
    for (i = 0; i < nWidth; ++i)
    {
        for (j = 0; j < nHeight; ++j)
        {
            //caculate the area of each area
            if (getPixel(i,j) != 255)
            {
                ColorCount[getPixel(i,j)]++;
            }
        }
    }
    //get rid of noise point
    for (i = 0; i < nWidth; ++i)
    {
        for (j = 0; j < nHeight; ++j)
        {
            if (ColorCount[getPixel(i,j)] <= pArea)
            {
                setPixel(i,j,WHITE);
            }
        }
    }
    for (i = 0; i < nWidth; ++i)
    {
        for (j = 0; j < nHeight; ++j)
        {
            if (getPixel(i,j) < WHITE)
            {
                setPixel(i,j,BLACK);
            }
        }
    }
}

     */


    //图片对比，相似度
    //ORB是是ORiented Brief的简称，是BRIEF算法的改进。
    // ORB采用贪婪穷举的方法得到了相关性较低的随机点对，
    // 还有一个改进就是对于随机点对，受噪声的影响很大BRIEF的办法就是对原图像滤波，
    // 降低噪声的影响，ORB不在使用像素点的直接比较，
    // 而是选择该像素为中心的一个小patch作为比较对象，提高了抗噪能力。
    /*int getORB(char * imagePatha,char * imagePathb){

        double t;

        t=getTickCount();

        Mat img_1 = imread(imagePatha);

        Mat img_2 = imread(imagePathb);

        if (!img_1.data || !img_2.data)   {

            cout << "error reading images " << endl;      return -1;

        }

        ORB orb;

        vector<KeyPoint> keyPoints_1, keyPoints_2;

        Mat descriptors_1, descriptors_2;

        orb(img_1, Mat(), keyPoints_1, descriptors_1);

        orb(img_2, Mat(), keyPoints_2, descriptors_2);

        BruteForceMatcher<HammingLUT> matcher;

        vector<DMatch> matches;

        matcher.match(descriptors_1, descriptors_2, matches);

        double max_dist = 0; double min_dist = 100;

        for( int i = 0; i < descriptors_1.rows; i++ )   {

            double dist = matches[i].distance;

            if( dist < min_dist ) min_dist = dist;

            if( dist > max_dist ) max_dist = dist;

        }

        printf("-- Max dist : %f \n", max_dist );

        printf("-- Min dist : %f \n", min_dist );

        std::vector< DMatch > good_matches;

        for( int i = 0; i < descriptors_1.rows; i++ )   {

            if( matches[i].distance < 0.6*max_dist ){

                good_matches.push_back(matches[i]);

            }

        }

        t=getTickCount()-t;

        t=t*1000/getTickFrequency();

        Mat img_matches;

        drawMatches(img_1, keyPoints_1, img_2, keyPoints_2,good_matches, img_matches,

                Scalar::all(-1), Scalar::all(-1),vector<char>(),

                DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

        imshow( "Match", img_matches);

        printf( "%f ms\n", t );

        cvWaitKey(0);

        return 0;

    }*/

}

